#!/usr/bin/env python
# encoding: utf-8

# Commentaires sur le devoir : 

# J'ai choisi de ne pas être en logarithmique pour les volumes et de ne pas les faire en dB mais bien de 0 à 1. Cela me semblait plus intuitif.
# Les effets choisient ne sont qu'a titre indicatif. Le but de ce travail etait plutôt de créer la matrice de base pour ensuite peaufiner niveau sonore dans le cours de Pyo 2.
# Dans certain cas (dont celui de la reverb) les paramètres sont exprimes en pourcentage.
# Dans le Bit Reducer, seul le scale est de 0 a 1000. Ce choix est personnel.
# Le Xfade loop (Looper) est mis de 0 a 10 secondes... je n'ai pas cru bon de le faire reagir a la longueur de l'echantillon...

# On avait convenu que le TP1 comptait pour 20 % et le TP final pour 80 %. Tu as deja corriger mon TP1 (10 / 10)

# Et finalement, un enorme merci pour ton aide et ta patience. Vraiment ! 

import wx
from pyo import *
from pyolib._wxwidgets import VuMeter, ControlSlider
import os

s = Server(sr=48000, nchnls=2, buffersize=512, duplex=1).boot()
s.recordOptions(sampletype = 1)
s.amp = 1

# Son Ram ordinateur
class Audio:
    def __init__(self):
        self.table = SndTable([SNDS_PATH+"/transparent.aif",SNDS_PATH+"/transparent.aif"])
        self.input = Looper(table=self.table, pitch = 1, start=0, dur = 1, xfade = 10, startfromloop = True, mul = 1, interp =4 , autosmooth = True)
        self.input
        self.input1 = Input(chnl = 0, mul = 1)
        self.input1
        self.lentable = self.table.getDur(False)
        self.startsl = None  
        self.endsl = None

    # Retour du signal audio Ram
    def sig(self):
        return self.input
        
    # Retour du signal audio entree 1
    def sig1(self):
        return self.input1
        
    # Load nouveau son
    def changeTable(self, snd):
        self.table.sound = snd
        self.input.freq = self.table.getRate()
        self.lentable = self.table.getDur(False)
        if self.startsl != None:
            print self.lentable
            self.startsl.SetRange(0, self.lentable)
            self.endsl.SetRange(0, self.lentable)
    
    def setSliders(self, start, end):
        self.startsl = start
        self.endsl = end

class MyFrame(wx.Frame):
    def __init__(self, parent=None, title="Matrice", pos=(100,100), size=(450,500), switcher=None):
        wx.Frame.__init__(self, parent, id=-1, title=title, pos=pos, size=size)
        
        # Event sur la fermeture du main frame
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        
        self.switcher = switcher
        self.audio = audio
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour("#DDDDDD")
             
        # Meter amplitude son RAM
        self.meter = VuMeter(self.panel, numSliders=2)
        self.meter.SetPosition((10,20))
        
        # Assignation du meter au serveur
        s._server.setAmpCallable(self.meter)
        
        # Bouton pour ouvrir un dialogue standard et sélectionner un nouveau son
        self.chooseButton = wx.Button(self.panel, id=-1, label="Load snd...", pos=(10,90))
        self.chooseButton.Bind(wx.EVT_BUTTON, self.loadSnd)

        # Slider Volume In Entree 1
        self.volumeentree1Text = wx.StaticText(self.panel, id=-1, label=" Volume In Entree 1 / 1", pos=(20,162), size=wx.DefaultSize)
        self.volumeentree1 = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.5, pos=(20, 182), size=(240, 16), log=False, outFunction=self.changeVolume2, integer=False, powoftwo=False, backColour=None)
        
        # Slider Pitch Loop
        self.changepitchText = wx.StaticText(self.panel, id=-1, label=" Pitch Loop / 4", pos=(20,202), size=wx.DefaultSize)
        self.changepitch = ControlSlider(self.panel, minvalue=0.1, maxvalue=4, init=1, pos=(20, 222), size=(240, 16), log=False, outFunction=self.changePitch, integer=False, powoftwo=False, backColour=None)
        
        # Slider Start Loop
        self.changestartText = wx.StaticText(self.panel, id=-1, label=" Start Loop (s)", pos=(20,242), size=wx.DefaultSize)
        self.changestart = ControlSlider(self.panel, minvalue=0, maxvalue=self.audio.lentable, init=0, pos=(20, 262), size=(240, 16), log=False, outFunction=self.changeStart, integer=False, powoftwo=False, backColour=None)

        # Slider Dur Loop
        self.changedurText = wx.StaticText(self.panel, id=-1, label=" Duration Loop (s)", pos=(20,282), size=wx.DefaultSize)
        self.changedur = ControlSlider(self.panel, minvalue=0, maxvalue=self.audio.lentable, init=self.audio.lentable, pos=(20, 302), size=(240, 16), log=False, outFunction=self.changeDur, integer=False, powoftwo=False, backColour=None)
        
        # Change valeur slideur Start Time et Dur Time du Looper
        self.audio.setSliders(self.changestart, self.changedur)

        # Slider Xfade Loop
        self.changefadeText = wx.StaticText(self.panel, id=-1, label=" Xfade Loop (s) / 10", pos=(20,322), size=wx.DefaultSize)
        self.changefade = ControlSlider(self.panel, minvalue=0.01, maxvalue=10, init= 0.5, pos=(20, 342), size=(240, 16), log=False, outFunction=self.changeFade, integer=False, powoftwo=False, backColour=None)

        # Bouton Bit Reducer
        self.bitframeText = wx.StaticText(self.panel, id=-1, label="Bit Reducer", pos=(260,37))
        self.bitframe = wx.ToggleButton(self.panel, id=-1, label="X", pos=(260,57))
        self.bitframe.Bind(wx.EVT_TOGGLEBUTTON, self.openPageBit)
        
        # Bouton Reverb
        self.bitframeText = wx.StaticText(self.panel, id=-1, label="Reverb", pos=(350,37))
        self.bitframe = wx.ToggleButton(self.panel, id=-1, label="X", pos=(340,57))
        self.bitframe.Bind(wx.EVT_TOGGLEBUTTON, self.openReverb)
        
        # Bouton Serveur
        self.serveurText = wx.StaticText(self.panel, id=-1, label="GO", pos=(205,37))
        self.serveur = wx.ToggleButton(self.panel, id=-1, label="X", pos=(180,57))
        self.serveur.Bind(wx.EVT_TOGGLEBUTTON, self.handleAudio)
                
        # Bouton Mixeur
        self.mixeurfText = wx.StaticText(self.panel, id=-1, label="Mixeur", pos=(30,37))
        self.mixeurf = wx.ToggleButton(self.panel, id=-1, label="X", pos=(20,57))
        self.mixeurf.Bind(wx.EVT_TOGGLEBUTTON, self.openPageMixeur)
         
        # Bouton Record
        self.recordmasterText = wx.StaticText(self.panel, id=-1, label="Record", pos=(110,37))
        self.recordmaster = wx.ToggleButton(self.panel, id=-1, label="X", pos=(100,57))
        self.recordmaster.Bind(wx.EVT_TOGGLEBUTTON, self.recordMaster)
        
   # Ferme de facon propre le serveur
    def OnClose(self, evt):
        print "Fin..."
        if s.getIsStarted():
            s.stop()
            time.sleep(.25)
        s.shutdown()
        time.sleep(.25)
        self.Destroy()
        
    # Part le serveur lors du On de Son Ram ou entree 1                   
    def handleAudio(self, evt):
        if evt.GetInt() == 1:
            s.start()
        else:
            s.stop()
            
    def recordMaster(self, evt):
        if evt.GetInt() == 1:    
            s.recstart()
        else:
            s.recstop()
      
    # Ouverture du Bit Reducer        
    def openPageBit(self, evt):
        if evt.GetInt() == 1:    
            BitReducerF.Show()
        else:
            BitReducerF.Hide()

    # Ouverture du Reverb    
    def openReverb(self, evt):
        if evt.GetInt() == 1:    
            ReverbF.Show()
        else:
            ReverbF.Hide()
                                
    # Ouverture du Mixeur        
    def openPageMixeur(self, evt):
        if evt.GetInt() == 1:
            MixeurF.Show()
        else:
            MixeurF.Hide()
            
    def setSound(self, evt):
        x = self.pit.GetValue() * 0.001
        self.audio.table.setSound = (evt.GetString())
        self.audio.input.freq = self.audio.table.getRate() * x
        
    # Volume In Entree 1
    def changeVolume2(self, value):
        x = value
        self.audio.input1.mul = x

    # Pitch Loop
    def changePitch(self, value):
        x = value
        self.audio.input.pitch = x

    # Start Loop
    def changeStart(self, value):
        x = value
        self.audio.input.start = x
        
    # Duration Loop
    def changeDur(self, value):
        x = value
        self.audio.input.dur = x

    # Xfade Loop
    def changeFade(self, value):
        x = value
        self.audio.input.xfade = x
        
    # Filtrage des fichiers disponibles          
    def loadSnd(self, evt):
        wildcard = "All files|*.*|" \
                   "AIFF file|*.aif;*.aiff;*.aifc;*.AIF;*.AIFF;*.Aif;*.Aiff|" \
                   "Wave file|*.wav;*.wave;*.WAV;*.WAVE;*.Wav;*.Wave"
        dlg = wx.FileDialog(self, message="Choose a new soundfile...", wildcard=wildcard, style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if path != "":
                self.switcher.changeTable(path)  
        dlg.Destroy()
                 
# Deuxième fenêtre qui apparait lorsqu'on clique sur le FX Bit Reducer
class BitReducerFrame(wx.Frame):
    def __init__(self, parent, title, pos, size, process):
        wx.Frame.__init__(self, parent, id=-1, title=title, pos=pos, size=size)
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour("#DDDDDD")
        self.process = process
        
        # Trig de preset
        self.presetNum = 0
        self.metro = Metro(time=2)
        self.trigger = TrigFunc(self.metro, function=self.trigPreset)
        
        # Bouton Preset 1 Bit Reducer
        self.preset1saveText = wx.StaticText(self.panel, id=-1, label="Preset 1", pos=(30,200), size=wx.DefaultSize)
        self.preset1saveButton = wx.Button(self.panel, id=-1, label="Save", pos=(20,220))
        self.preset1saveButton.Bind(wx.EVT_BUTTON, self.getpreset1BitReducer)

        # Bouton Preset 1 Bit Reducer
        self.preset1recallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(20,250))
        self.preset1recallButton.Bind(wx.EVT_BUTTON, self.setpreset1BitReducer)

        # Bouton Preset 2 Bit Reducer
        self.preset2saveText = wx.StaticText(self.panel, id=-1, label="Preset 2", pos=(110,200), size=wx.DefaultSize)
        self.preset2saveButton = wx.Button(self.panel, id=-1, label="Save", pos=(100,220))
        self.preset2saveButton.Bind(wx.EVT_BUTTON, self.getpreset2BitReducer)

        # Bouton Preset 2 Bit Reducer
        self.preset2recallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(100,250))
        self.preset2recallButton.Bind(wx.EVT_BUTTON, self.setpreset2BitReducer)
        
        # Bouton Preset 3 Bit Reducer
        self.preset3saveText = wx.StaticText(self.panel, id=-1, label="Preset 3", pos=(190,200), size=wx.DefaultSize)
        self.preset3saveButton = wx.Button(self.panel, id=-1, label="Save", pos=(180,220))
        self.preset3saveButton.Bind(wx.EVT_BUTTON, self.getpreset3BitReducer)

        # Bouton Preset 3 Bit Reducer
        self.preset3recallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(180,250))
        self.preset3recallButton.Bind(wx.EVT_BUTTON, self.setpreset3BitReducer)

        # Slider Temps Trig
        self.timetrigText = wx.StaticText(self.panel, id=-1, label="Temps Preset (s) / 5", pos=(300,200), size=wx.DefaultSize)
        self.timetrig = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(300, 220), size=(160, 16), log=False, outFunction=self.timeTrig, integer=False, powoftwo=False, backColour=None)
                                        
        # Slider Bit Depth valeur minimale
        self.bitminiText = wx.StaticText(self.panel, id=-1, label="Bit Depth Minimum / 0", pos=(220,20), size=wx.DefaultSize)
        self.bitmini = ControlSlider(self.panel, minvalue=0, maxvalue=24, init=4, pos=(220, 40), size=(160, 16), log=False, outFunction=self.bitDepthMinimum, integer=True, powoftwo=False, backColour=None)

        # Slider Bit Depth valeur maximale
        self.bitmaxiText = wx.StaticText(self.panel, id=-1, label="Bit Depth Maximum / 24", pos=(220,60), size=wx.DefaultSize)
        self.bitmaxi = ControlSlider(self.panel, minvalue=0, maxvalue=24, init=20, pos=(220, 80), size=(160, 16), log=False, outFunction=self.bitDepthMaximum, integer=True, powoftwo=False, backColour=None)
                     
        # Slider Scale valeur minimale
        self.scaleminimumText = wx.StaticText(self.panel, id=-1, label="Scale Minimum / 100", pos=(20,20), size=wx.DefaultSize)
        self.scaleminimum = ControlSlider(self.panel, minvalue=100, maxvalue=1000, init=100, pos=(20, 40), size=(160, 16), log=False, outFunction=self.scaleMinimum, integer=True, powoftwo=False, backColour=None)

        # Slider Scale valeur maximale
        self.scalemaximumText = wx.StaticText(self.panel, id=-1, label="Scale Maximum / 1000", pos=(20,60), size=wx.DefaultSize)
        self.scalemaximum = ControlSlider(self.panel, minvalue=100, maxvalue=1000, init=500, pos=(20, 80), size=(160, 16), log=False, outFunction=self.scaleMaximum, integer=True, powoftwo=False, backColour=None)
               
        # Slider Beat Scale
        self.beatscaleText = wx.StaticText(self.panel, id=-1, label="Beat Time Scale (s) / 5", pos=(20,100), size=wx.DefaultSize)
        self.beatscale = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(20, 122), size=(160, 16), log=False, outFunction=self.changeBeatScale, integer=False, powoftwo=False, backColour=None)

        # Slider Beat Bit Depth
        self.beatbitText = wx.StaticText(self.panel, id=-1, label="Beat Time Bit Depth (s) / 5", pos=(220,100), size=wx.DefaultSize)
        self.beatbit = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(220, 122), size=(160, 16), log=False, outFunction=self.changeBeatBit, integer=False, powoftwo=False, backColour=None)

        # Bouton Trig Preset GO
        self.trigpresetButton = wx.Button(self.panel, id=-1, label="Trig", pos=(500,220))
        self.trigpresetButton.Bind(wx.EVT_BUTTON, self.startLoopingPreset)
        
        # Bouton Trig Preset OFF
        self.trigpresetstopButton = wx.Button(self.panel, id=-1, label="Stop", pos=(500,250))
        self.trigpresetstopButton.Bind(wx.EVT_BUTTON, self.stopLoopingPreset)
                        
    def bitDepthMinimum(self, value):
        x = value
        self.process.valeurminimale = int(x)
        self.process.updateSequence()

    def bitDepthMaximum(self, value):
        y = value
        self.process.valeurmaximale = int(y)
        self.process.updateSequence()
     
    def scaleMinimum(self, value):
        x = value
        self.process.valeurminimalescale = int(x)
        self.process.updateScale()

    def scaleMaximum(self, value):
        x = value
        self.process.valeurmaximalescale = int(x)
        self.process.updateScale()

    def changeBeatScale(self, value):
        x = value
        self.process.updateBeatScale(x)
        
    def changeBeatBit(self, value):
        x = value
        self.process.updateBeatBit(x)

    # Gestion de preset du bit reducer / Les metronomes ne sont pas inclus dans les preset... choix personnel
    
    # Ecriture du preset 1
    def getpreset1BitReducer(self, evt=None):
        dic = {"valeurminimalebit": self.process.valeurminimale, "valeurmaximalebit": self.process.valeurmaximale, "valeurminimalescale" : self.process.valeurminimalescale, "valeurmaximalescale" : self.process.valeurmaximalescale}
        f = open("BitReducerPreset1", "w")
        f.write(str(dic))
        f.close()
        
    # Lecture du preset 1
    def setpreset1BitReducer(self, evt=None):
        f = open("BitReducerPreset1", "r")
        text = f.read()
        f.close()
        dic = eval(text)
        
        # Preset Bit
        self.process.valeurminimale = dic["valeurminimalebit"]
        self.bitmini.SetValue(int(dic["valeurminimalebit"]))
        self.process.valeurmaximale = dic["valeurmaximalebit"]
        self.bitmaxi.SetValue(int(dic["valeurmaximalebit"]))
        self.process.updateSequence()
        
        # Preset Scale
        self.process.valeurminimalescale = dic["valeurminimalescale"]
        self.scaleminimum.SetValue(int(dic["valeurminimalescale"]))
        self.process.valeurmaximalescale = dic["valeurmaximalescale"]
        self.scalemaximum.SetValue(int(dic["valeurmaximalescale"]))
        self.process.updateScale()       
        
    # Ecriture du preset 2
    def getpreset2BitReducer(self, evt=None):
        dic = {"valeurminimalebit": self.process.valeurminimale, "valeurmaximalebit": self.process.valeurmaximale, "valeurminimalescale" : self.process.valeurminimalescale, "valeurmaximalescale" : self.process.valeurmaximalescale}
        f = open("BitReducerPreset2", "w")
        f.write(str(dic))
        f.close()
        
    # Lecture du preset 2
    def setpreset2BitReducer(self, evt=None):
        f = open("BitReducerPreset2", "r")
        text = f.read()
        f.close()
        dic = eval(text)
        
        # Preset Bit
        self.process.valeurminimale = dic["valeurminimalebit"]
        self.bitmini.SetValue(int(dic["valeurminimalebit"]))
        self.process.valeurmaximale = dic["valeurmaximalebit"]
        self.bitmaxi.SetValue(int(dic["valeurmaximalebit"]))
        self.process.updateSequence()
        
        # Preset Scale
        self.process.valeurminimalescale = dic["valeurminimalescale"]
        self.scaleminimum.SetValue(int(dic["valeurminimalescale"]))
        self.process.valeurmaximalescale = dic["valeurmaximalescale"]
        self.scalemaximum.SetValue(int(dic["valeurmaximalescale"]))
        self.process.updateScale()

    # Ecriture du preset 3
    def getpreset3BitReducer(self, evt=None):
        dic = {"valeurminimalebit": self.process.valeurminimale, "valeurmaximalebit": self.process.valeurmaximale, "valeurminimalescale" : self.process.valeurminimalescale, "valeurmaximalescale" : self.process.valeurmaximalescale}
        f = open("BitReducerPreset3", "w")
        f.write(str(dic))
        f.close()

    # Lecture du preset 3
    def setpreset3BitReducer(self, evt=None):
        f = open("BitReducerPreset3", "r")
        text = f.read()
        f.close()
        dic = eval(text)

        # Preset Bit
        self.process.valeurminimale = dic["valeurminimalebit"]
        self.bitmini.SetValue(int(dic["valeurminimalebit"]))
        self.process.valeurmaximale = dic["valeurmaximalebit"]
        self.bitmaxi.SetValue(int(dic["valeurmaximalebit"]))
        self.process.updateSequence()

        # Preset Scale
        self.process.valeurminimalescale = dic["valeurminimalescale"]
        self.scaleminimum.SetValue(int(dic["valeurminimalescale"]))
        self.process.valeurmaximalescale = dic["valeurmaximalescale"]
        self.scalemaximum.SetValue(int(dic["valeurmaximalescale"]))
        self.process.updateScale()
                    
    # Part le trig
    def startLoopingPreset(self, evt):
        self.metro.play()
        
    # Arrete le trig
    def stopLoopingPreset(self, evt):
        self.metro.stop()
        
    # Appellation des preset par le trig
    def trigPreset(self):       
        # Prepare le prochain preset avec wrap around sur le nombre total de presets (total = % TOTAL)
        self.presetNum = (self.presetNum + 1) % 3

        if self.presetNum == 0:
            self.setpreset1BitReducer()
            print 'Trig Preset 1'
            
        elif self.presetNum == 1:
            self.setpreset2BitReducer()
            print 'Trig Preset 2'
            
        elif self.presetNum == 2:
            self.setpreset3BitReducer()
            print 'Trig Preset 3'

    def timeTrig(self, value):
        x = value
        self.metro.time = x

# Deuxième fenêtre qui apparait lorsqu'on clique sur le FX Delay
class ReverbFrame(wx.Frame):
    def __init__(self, parent, title, pos, size, process):
        wx.Frame.__init__(self, parent, id=-1, title=title, pos=pos, size=size)
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour("#DDDDDD")
        self.process = process

        # Trig de preset
        self.presetNum = 0
        self.metro = Metro(time=2)
        self.trigger = TrigFunc(self.metro, function=self.trigPreset)
        
        # Bouton Preset 1 Reverb
        self.preset1reverbsaveText = wx.StaticText(self.panel, id=-1, label="Preset 1", pos=(30,200), size=wx.DefaultSize)
        self.preset1reverbsaveButton = wx.Button(self.panel, id=-1, label="Save", pos=(20,220))
        self.preset1reverbsaveButton.Bind(wx.EVT_BUTTON, self.getpreset1Reverb)

        # Bouton Preset 1 Reverb
        self.preset1reverbrecallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(20,250))
        self.preset1reverbrecallButton.Bind(wx.EVT_BUTTON, self.setpreset1Reverb)
        
        # Bouton Preset 2 Reverb
        self.preset2reverbsaveText = wx.StaticText(self.panel, id=-1, label="Preset 2", pos=(110,200), size=wx.DefaultSize)
        self.preset2reverbsaveButton = wx.Button(self.panel, id=-1, label="Save", pos=(100,220))
        self.preset2reverbsaveButton.Bind(wx.EVT_BUTTON, self.getpreset2Reverb)

        # Bouton Preset 2 Reverb
        self.preset2reverbrecallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(100,250))
        self.preset2reverbrecallButton.Bind(wx.EVT_BUTTON, self.setpreset2Reverb)
        
        # Bouton Preset 3 Reverb
        self.preset3reverbsaveText = wx.StaticText(self.panel, id=-1, label="Preset 3", pos=(190,200), size=wx.DefaultSize)
        self.preset3reverbsaveButton = wx.Button(self.panel, id=-1, label="Save", pos=(180,220))
        self.preset3reverbsaveButton.Bind(wx.EVT_BUTTON, self.getpreset3Reverb)

        # Bouton Preset 3 Reverb
        self.preset3reverbrecallButton = wx.Button(self.panel, id=-1, label="Recall", pos=(180,250))
        self.preset3reverbrecallButton.Bind(wx.EVT_BUTTON, self.setpreset3Reverb)        

        # Slider Temps Trig
        self.timetrigreverbText = wx.StaticText(self.panel, id=-1, label="Temps Preset (s) / 5 ", pos=(300,200), size=wx.DefaultSize)
        self.timetrigreverb = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(300, 220), size=(160, 16), log=False, outFunction=self.timeTrigReverb, integer=False, powoftwo=False, backColour=None)
                
        # Slider size valeur minimale
        self.sizeminiText = wx.StaticText(self.panel, id=-1, label="Size Minimum %", pos=(220,20), size=wx.DefaultSize)
        self.sizemini = ControlSlider(self.panel, minvalue=0, maxvalue=100, init=25, pos=(220, 40), size=(160, 16), log=False, outFunction=self.sizeMinimum, integer=True, powoftwo=False, backColour=None)

        # Slider size valeur maximale
        self.sizemaxiText = wx.StaticText(self.panel, id=-1, label="Size Maximum %", pos=(220,60), size=wx.DefaultSize)
        self.sizemaxi = ControlSlider(self.panel, minvalue=0, maxvalue=100, init=85, pos=(220, 80), size=(160, 16), log=False, outFunction=self.sizeMaximum, integer=True, powoftwo=False, backColour=None)

        # Slider Beat size
        self.beatsizeText = wx.StaticText(self.panel, id=-1, label="Beat Size (s) / 5 ", pos=(220,100), size=wx.DefaultSize)
        self.beatsize = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(220, 122), size=(160, 16), log=False, outFunction=self.changeBeatSize, integer=False, powoftwo=False, backColour=None)

        # Slider Damp valeur minimale
        self.dampminimumText = wx.StaticText(self.panel, id=-1, label="Damp Minimum %", pos=(20,20), size=wx.DefaultSize)
        self.dampminimum = ControlSlider(self.panel, minvalue=0, maxvalue=100, init=10, pos=(20, 40), size=(160, 16), log=False, outFunction=self.dampMinimum, integer=True, powoftwo=False, backColour=None)

        # Slider Damp valeur maximale
        self.dampmaximumText = wx.StaticText(self.panel, id=-1, label="Damp Maximum %", pos=(20,60), size=wx.DefaultSize)
        self.dampmaximum = ControlSlider(self.panel, minvalue=0, maxvalue=100, init=90, pos=(20, 80), size=(160, 16), log=False, outFunction=self.dampMaximum, integer=True, powoftwo=False, backColour=None)

        # Slider Beat Damp
        self.beatdampText = wx.StaticText(self.panel, id=-1, label="Beat Damp (s) / 5 ", pos=(20,100), size=wx.DefaultSize)
        self.beatdamp = ControlSlider(self.panel, minvalue=0.1, maxvalue=5, init=2, pos=(20, 122), size=(160, 16), log=False, outFunction=self.changeDampTime, integer=False, powoftwo=False, backColour=None)

        # Bouton Trig Preset GO
        self.trigpresetButton = wx.Button(self.panel, id=-1, label="Trig", pos=(500,220))
        self.trigpresetButton.Bind(wx.EVT_BUTTON, self.startLoopingPreset)
        
        # Bouton Trig Preset OFF
        self.trigpresetstopButton = wx.Button(self.panel, id=-1, label="Stop", pos=(500,250))
        self.trigpresetstopButton.Bind(wx.EVT_BUTTON, self.stopLoopingPreset)
                                
    def sizeMinimum(self, value):
        x = value
        self.process.valeurminimalesize = int(x)
        self.process.updateSize()

    def sizeMaximum(self, value):
        x = value
        self.process.valeurmaximalesize = int(x)
        self.process.updateSize()

    def dampMinimum(self, value):
        x = value
        self.process.valeurminimaledamp = int(x)
        self.process.updateDamp()

    def dampMaximum(self, value):
        x = value
        self.process.valeurmaximaledamp = int(x)
        self.process.updateDamp()
            
    def changeBeatSize(self, value):
        x = value
        self.process.updateBeatSize(x)       

    def changeDampTime(self, value):
        x = value
        self.process.updateDampTime(x)

    # Ecriture du preset 1
    def getpreset1Reverb(self, evt=None):
        dic = {"valeurminimalesize": self.process.valeurminimalesize, "valeurmaximalesize": self.process.valeurmaximalesize, "valeurminimaledamp" : self.process.valeurminimaledamp, "valeurmaximaledamp" : self.process.valeurmaximaledamp}
        f = open("ReverbPreset1", "w")
        f.write(str(dic))
        f.close()

    # Lecture du preset 1
    def setpreset1Reverb(self, evt=None):
        f = open("ReverbPreset1", "r")
        text = f.read()
        f.close()
        dic = eval(text)

        # Preset Size
        self.process.valeurminimalesize = dic["valeurminimalesize"]
        self.sizemini.SetValue(int(dic["valeurminimalesize"]))
        self.process.valeurmaximalesize = dic["valeurmaximalesize"]
        self.sizemaxi.SetValue(int(dic["valeurmaximalesize"]))
        self.process.updateSize()

        # Preset Damp
        self.process.valeurminimaledamp = dic["valeurminimaledamp"]
        self.dampminimum.SetValue(int(dic["valeurminimaledamp"]))
        self.process.valeurmaximaledamp = dic["valeurmaximaledamp"]
        self.dampmaximum.SetValue(int(dic["valeurmaximaledamp"]))
        self.process.updateDamp()

    # Ecriture du preset 2
    def getpreset2Reverb(self, evt=None):
        dic = {"valeurminimalesize": self.process.valeurminimalesize, "valeurmaximalesize": self.process.valeurmaximalesize, "valeurminimaledamp" : self.process.valeurminimaledamp, "valeurmaximaledamp" : self.process.valeurmaximaledamp}
        f = open("ReverbPreset2", "w")
        f.write(str(dic))
        f.close()

    # Lecture du preset 2
    def setpreset2Reverb(self, evt=None):
        f = open("ReverbPreset2", "r")
        text = f.read()
        f.close()
        dic = eval(text)

        # Preset Size
        self.process.valeurminimalesize = dic["valeurminimalesize"]
        self.sizemini.SetValue(int(dic["valeurminimalesize"]))
        self.process.valeurmaximalesize = dic["valeurmaximalesize"]
        self.sizemaxi.SetValue(int(dic["valeurmaximalesize"]))
        self.process.updateSize()

        # Preset Damp
        self.process.valeurminimaledamp = dic["valeurminimaledamp"]
        self.dampminimum.SetValue(int(dic["valeurminimaledamp"]))
        self.process.valeurmaximaledamp = dic["valeurmaximaledamp"]
        self.dampmaximum.SetValue(int(dic["valeurmaximaledamp"]))
        self.process.updateDamp()      

    # Ecriture du preset 3
    def getpreset3Reverb(self, evt=None):
        dic = {"valeurminimalesize": self.process.valeurminimalesize, "valeurmaximalesize": self.process.valeurmaximalesize, "valeurminimaledamp" : self.process.valeurminimaledamp, "valeurmaximaledamp" : self.process.valeurmaximaledamp}
        f = open("ReverbPreset3", "w")
        f.write(str(dic))
        f.close()

    # Lecture du preset 3
    def setpreset3Reverb(self, evt=None):
        f = open("ReverbPreset3", "r")
        text = f.read()
        f.close()
        dic = eval(text)

        # Preset Size
        self.process.valeurminimalesize = dic["valeurminimalesize"]
        self.sizemini.SetValue(int(dic["valeurminimalesize"]))
        self.process.valeurmaximalesize = dic["valeurmaximalesize"]
        self.sizemaxi.SetValue(int(dic["valeurmaximalesize"]))
        self.process.updateSize()

        # Preset Damp
        self.process.valeurminimaledamp = dic["valeurminimaledamp"]
        self.dampminimum.SetValue(int(dic["valeurminimaledamp"]))
        self.process.valeurmaximaledamp = dic["valeurmaximaledamp"]
        self.dampmaximum.SetValue(int(dic["valeurmaximaledamp"]))
        self.process.updateDamp()
                      
    # Part le trig
    def startLoopingPreset(self, evt):
        self.metro.play()

    # Arrete le trig
    def stopLoopingPreset(self, evt):
        self.metro.stop()

    # Appellation des preset par le trig
    def trigPreset(self):       
        # Prepare le prochain preset avec wrap around sur le nombre total de presets (total = % TOTAL)
        self.presetNum = (self.presetNum + 1) % 3

        if self.presetNum == 0:
            self.setpreset1Reverb()
            print 'Trig Preset Reverb 1'

        elif self.presetNum == 1:
            self.setpreset2Reverb()
            print 'Trig Preset Reverb 2'
        
        elif self.presetNum == 2:
            self.setpreset3Reverb()
            print 'Trig Preset Reverb 3'

    def timeTrigReverb(self, value):
        x = value
        self.metro.time = x
                                
class MixeurFrame(wx.Frame):
    def __init__(self, parent, title, pos, size, process):
        wx.Frame.__init__(self, parent, id=-1, title=title, pos=pos, size=size)
        self.panel = wx.Panel(self)
        self.panel.SetBackgroundColour("#DDDDDD")
        self.mixeur = mixeur

        # Slider Volume Son Ram Direct Out
        self.volumeramdirectText = wx.StaticText(self.panel, id=-1, label="Volume Son Ram Direct / 1", pos=(20,20), size=wx.DefaultSize)
        self.volumeramdirect = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(20, 40), size=(160, 16), log=False, outFunction=self.volumeRamDirect, integer=False, powoftwo=False, backColour=None)

        # Slider Volume Entree 1 Direct Out
        self.volumeentree1directText = wx.StaticText(self.panel, id=-1, label="Volume Entree 1 Direct / 1", pos=(20,60), size=wx.DefaultSize)
        self.volumeentree1direct = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(20, 80), size=(160, 16), log=False, outFunction=self.volumeEntree1Direct, integer=False, powoftwo=False, backColour=None)

        # Slider Volume Son Ram Bit Reducer
        self.volumerambitreduceText = wx.StaticText(self.panel, id=-1, label="Volume Son Ram Bit Reducer / 1", pos=(220,20), size=wx.DefaultSize)
        self.volumerambitreduce = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(220, 40), size=(160, 16), log=False, outFunction=self.volumeRamBit, integer=False, powoftwo=False, backColour=None)

        # Slider Entree 1 Bit Reducer
        self.volumeentree1bitreduceText = wx.StaticText(self.panel, id=-1, label="Volume Entree 1 Bit Reducer / 1", pos=(220,60), size=wx.DefaultSize)
        self.volumeentree1bitreduce = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(220, 80), size=(160, 16), log=False, outFunction=self.volumeEntree1Bit, integer=False, powoftwo=False, backColour=None)

        # Slider Volume Son Ram Delai
        self.volumeramdelaiText = wx.StaticText(self.panel, id=-1, label="Volume Son Ram Reverb / 1", pos=(20,105), size=wx.DefaultSize)
        self.volumeramdelai = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(20, 125), size=(160, 16), log=False, outFunction=self.volumeRamDelai, integer=False, powoftwo=False, backColour=None)

        # Slider Volume Entree 1 Delai
        self.volumeentree1delaiText = wx.StaticText(self.panel, id=-1, label="Volume Entree 1 Reverb / 1", pos=(220,105), size=wx.DefaultSize)
        self.volumeentree1delai = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(220, 125), size=(160, 16), log=False, outFunction=self.volumeEntree1Delai, integer=False, powoftwo=False, backColour=None)

        # Slider Volume BR dans Reverb
        self.volumebrdelaiText = wx.StaticText(self.panel, id=-1, label="Volume BR dans Reverb / 1", pos=(220,150), size=wx.DefaultSize)
        self.volumebrdelai = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(220, 170), size=(160, 16), log=False, outFunction=self.volumeBitReduceDansDelai, integer=False, powoftwo=False, backColour=None)
        
        # Slider Volume Reverb dans BR
        self.volumereverbbrText = wx.StaticText(self.panel, id=-1, label="Volume Reverb dans BR / 1", pos=(20,150), size=wx.DefaultSize)
        self.volumereverbbr = ControlSlider(self.panel, minvalue=0.00, maxvalue=1, init= 0.00, pos=(20, 170), size=(160, 16), log=False, outFunction=self.volumeReverbDansBitReduce, integer=False, powoftwo=False, backColour=None)
        self.volumereverbbr.Bind(wx.EVT_SLIDER, self.volumeReverbDansBitReduce)
                                
    # Volume Son Ram Direct Out        
    def volumeRamDirect(self, value):
        x = value
        self.ramdirectout = x
        self.mixeur.mm.setAmp(0, 0, self.ramdirectout)

    # Volume Entree 1 Direct Out
    def volumeEntree1Direct(self, value):
        x = value
        self.entree1directout = x
        self.mixeur.mm.setAmp(1, 0, self.entree1directout)

    # Volume Son Ram Bit Reducer
    def volumeRamBit(self, value):
        x = value
        self.volumerambit = x
        self.mixeur.mm.setAmp(0, 1, self.volumerambit)

    # Volume Entree 1 Bit Reducer
    def volumeEntree1Bit(self, value):
        x = value
        self.volumeentree1bitreduce = x
        self.mixeur.mm.setAmp(1, 1, self.volumeentree1bitreduce)

    # Volume Son Ram Delai
    def volumeRamDelai(self, value):
        x = value
        self.volumeramdelai = x
        self.mixeur.mm.setAmp(0, 2, self.volumeramdelai)

    # Volume Entree 1 Delai
    def volumeEntree1Delai(self, value):
        x = value
        self.volumeentree1delai = x
        self.mixeur.mm.setAmp(1, 2, self.volumeentree1delai)

    # Volume Br dans Reverb
    def volumeBitReduceDansDelai(self, value):
        x = value
        self.volumebrdelai = x
        self.mixeur.mm.setAmp(2, 2, self.volumebrdelai)

    # Volume Reverb dans BR
    def volumeReverbDansBitReduce(self, value):
        x = value
        self.volumereverbbr = x
        self.mixeur.mm.setAmp(2, 2, self.volumereverbbr)
                                                
# Mixeur de sources versus FX
class Mixeur:
    def __init__(self, audio):
        self.sonram = audio.sig()
        self.entree1 = audio.sig1() 
        self.mm = Mixer(outs = 3, chnls = 2, time = 0.25)
        self.mm.addInput(0, self.sonram)
        self.mm.addInput(1, self.entree1)
        # Amplitude de son ram vers Direct Out
        self.mm.setAmp(0, 0, 0)
        # Amplitude de entree 1 vers Direct Out
        self.mm.setAmp(1, 0, 0)
        # Amplitude de son ram vers Bit Reducer
        self.mm.setAmp(0, 1, 0)
        # Amplitude de entree 1 vers Bit Reducer
        self.mm.setAmp(1, 1, 0)
        # Amplitude de son ram vers Reverb
        self.mm.setAmp(0, 2, 0)
        # Amplitude de son entree 1 vers Reverb
        self.mm.setAmp(1, 2, 0)
        # Sortie directe
        self.direct = (self.mm[0])
        # Sortie vers Bit Reducer
        self.fx1 = (self.mm[1])
        # Sortie vers Reverb
        self.fx2 = (self.mm[2])
        
    # Sortie Direct Out
    def mixeurOut0(self):
        return self.direct
    # Sortie FX 1 - Bit Reducer
    def mixeurOut1(self):
        return self.fx1
    # Sortie FX 2 - Reverb
    def mixeurOut2(self):
        return self.fx2
        
class DirectOut:
    def __init__(self, mixeur):
        self.audio =  mixeur.mixeurOut0()
        self.directOut = Sig(self.audio).out()
                
class BitReducer:
    def __init__(self, audio):
        self.audio = mixeur.mixeurOut1()
        self.valeurminimale = 5
        self.valeurmaximale = 10     
        self.valeurminimalescale = 100
        self.valeurmaximalescale = 1000
        self.metscale = Beat(time=.125, taps=16, w1=90, w2=50, w3=30).play()
        self.metbit = Beat(time=.125, taps=16, w1=90, w2=50, w3=30).play()
        initchoicebit = [i for i in range(self.valeurminimale, self.valeurmaximale)]
        initchoicescale = [i * 0.001 for i in range (self.valeurminimalescale, self.valeurmaximalescale)]
        self.sequencebitchoice = TrigChoice(self.metbit, choice=initchoicebit)
        self.sequencescalechoice = TrigChoice(self.metscale, choice=initchoicescale)
        self.bitreduce = Degrade(self.audio, bitdepth=self.sequencebitchoice, srscale=self.sequencescalechoice).out()
        
    def updateScale(self):
        self.sequencescalechoice.choice = [i * 0.001 for i in range(self.valeurminimalescale, self.valeurmaximalescale)]
        
    def updateSequence(self):
        self.sequencebitchoice.choice = [i for i in range(self.valeurminimale, self.valeurmaximale)]

    def updateBeatScale(self, value):
        self.metscale.time = value
        
    def updateBeatBit(self, value):
        self.metbit.time = value
        
    def retourBR(self):
        return self.bitreduce
        
class Reverb:
    def __init__(self, audio):
        self.audio = mixeur.mixeurOut2()
        self.valeurminimalesize = 0
        self.valeurmaximalesize = 100
        self.valeurminimaledamp = 0
        self.valeurmaximaledamp = 100
        self.metsize = Beat(time=.125, taps=16, w1=90, w2=50, w3=30).play()
        self.metdamp = Beat(time=.125, taps=16, w1=90, w2=50, w3=30).play()
        initchoicesize = [i*0.01 for i in range(self.valeurminimalesize, self.valeurmaximalesize)]
        initdampchoice = [i*0.01 for i in range(self.valeurminimaledamp, self.valeurmaximaledamp)]
        self.sequencesizechoice = TrigChoice(self.metsize, choice = initchoicesize)
        self.sequencedampchoice = TrigChoice(self.metdamp, choice = initdampchoice)
        self.reverb = Freeverb(self.audio, size=self.sequencesizechoice, damp=self.sequencedampchoice, bal = 1).out()
    
    def updateSize(self):
        self.sequencesizechoice.choice = [i * 0.01 for i in range(self.valeurminimalesize, self.valeurmaximalesize)]

    def updateDamp(self):
        self.sequencedampchoice.choice = [i* 0.01 for i in range(self.valeurminimaledamp, self.valeurmaximaledamp)]
        
    def updateBeatSize(self, value):
        self.metsize.time = value

    def updateDampTime(self, value):
        self.metdamp.time = value

    def retourReverb(self):
        return self.reverb
                
app = wx.PySimpleApp()

# Audio
audio = Audio()

# Mixeur
mixeur = Mixeur(audio)

# Direct Out
directOut = DirectOut(mixeur)

# Effets
bitreduce = BitReducer(audio)
reverb = Reverb(audio)

# Mixeur FX dans FX (update du mixeur apres les FX)
mixeur.mm.addInput(2, bitreduce.retourBR())
mixeur.mm.addInput(3, reverb.retourReverb())

# Amplitude de bitreducer dans Reverb / Amplitude de Reverb dans bitreducer
mixeur.mm.setAmp(2, 2, 0)
mixeur.mm.setAmp(3, 1, 0)

# Fenetre du Bit Reducer. Ouvre lorsqu'on clique sur le X.
BitReducerF = BitReducerFrame(None, title='Bit Reducer', pos=(700,100), size=(600,300), process=bitreduce)

# Fenetre du Reverb. Ouvre lorsqu'on clique sur le X.
ReverbF = ReverbFrame(None, title='Reverb', pos=(700,400), size=(600,300), process = reverb)

# Fenetre du Mixeur. Ouvre lorsqu'on clique sur le X.
MixeurF = MixeurFrame(None, title='Mixeur', pos=(100,600), size=(450,300), process=mixeur)

# Ouvre Matrice a l'ouverture de programme
mainFrame = MyFrame(switcher=audio)
mainFrame.Show()
app.MainLoop()